﻿using Common.Logging;
using Quartz;
using System.Data;
using System;
using System.Xml;
using CDService;
using System.Text;

namespace Panxch.CDService.Job
{
    public class ConvertJob : IJob
    {
        //日志构造者。
        private static readonly ILog Logger = LogManager.GetLogger(typeof(ConvertJob));
        delegate void AsyncCreateImage(string type, string syncDate);

        XmlDocument xmlDoc;
        string sourceDbConn = "", targetDbConn = "";
        string stationType = "";
        float cSO2 = 1, cCO = 1, cNO2 = 1, cO3 = 1, cPM10 = 1, cPM25 = 1;
        #region Implementation of IJob

        /// <summary>
        /// Called by the <see cref="T:Quartz.IScheduler" /> when a <see cref="T:Quartz.ITrigger" />
        /// fires that is associated with the <see cref="T:Quartz.IJob" />.
        /// </summary>
        /// <remarks>
        /// The implementation may wish to set a  result object on the
        /// JobExecutionContext before this method exits.  The result itself
        /// is meaningless to Quartz, but may be informative to
        /// <see cref="T:Quartz.IJobListener" />s or
        /// <see cref="T:Quartz.ITriggerListener" />s that are watching the job's
        /// execution.
        /// </remarks>
        /// <param name="context">The execution context.</param>
        public void Execute(IJobExecutionContext context)
        {
            string jobDes = context.JobDetail.Description;
            Logger.Info($"{jobDes}运行");

            //读取配置文件
            LoadXml();

            //站点同步
            int count = SyncAllStation();
            InsertSyncRecord(count);

            //数据转化
            ConvertData();
        }

        private void InsertSyncRecord(int count) {
            DateTime dt = DateTime.Now;
            string dtStr = new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, 0, 0).ToString("yyyy-MM-dd HH:mm:ss");
            string sql = string.Format("select count(1) from syncDataRecord where type='{0}' and syncDate='{1}'",stationType, dtStr);
            int c = int.Parse(SqlHelper.ExecuteScalar(sql, targetDbConn).ToString());
            if (c > 0) {
                return;
            }

            sql = string.Format("insert into syncDataRecord (type,syncDate,count,syncCount,status) values('{0}','{1}',{2},0,'1')",stationType, dtStr, count);
            if (SqlHelper.ExecuteSql(sql, targetDbConn) == 0)
            {
                //TODO将记录保存到缓存或者文本中，等待下一次任务计算的在尝试写入到数据库，后续加
            }
            
        }

        private void LoadXml()
        {
            Logger.Info("开始读取配置文件");
            string xmlPath = AppDomain.CurrentDomain.BaseDirectory + "Conf/config.xml";
            try
            {
                xmlDoc = new XmlDocument();
                xmlDoc.Load(xmlPath);
                sourceDbConn = xmlDoc.SelectSingleNode("config/SourceDataBase").Attributes["value"].Value;
                targetDbConn = xmlDoc.SelectSingleNode("config/TargetDataBase").Attributes["value"].Value;
                stationType = xmlDoc.SelectSingleNode("config/StationType").Attributes["value"].Value;

                if (!"1".Equals(stationType) && !"2".Equals(stationType))
                {
                    Logger.Error(String.Format("未知的站点类型：{0}，任务终止", stationType));
                    return;
                }

                Logger.Info(String.Format("当前运行站点类型：{0}", stationType.Equals("1") ? "市控站点" : "区控站点"));

            }
            catch (Exception e)
            {
                Logger.Error(String.Format("读取配置文件错误，任务终止，错误原因：{0}", e.Message));
                return;
            }

            cSO2 = GetConvertValue("SO2");
            cNO2 = GetConvertValue("NO2");
            cCO = GetConvertValue("CO");
            cO3 = GetConvertValue("O3");
            cPM10 = GetConvertValue("PM10");
            cPM25 = GetConvertValue("PM25");
            Logger.Info("配置文件读取完毕");
        }

        /// <summary>
        /// 获取转换值
        /// </summary>
        /// <param name="type">污染物类型</param>
        /// <returns></returns>
        private float GetConvertValue(string type)
        {
            try
            {
                return float.Parse(xmlDoc.SelectSingleNode(String.Format("config/ConvertUnit/{0}", type)).Attributes["value"].Value);
            }
            catch (Exception e)
            {
                return 1;
            }
        }

        private void ConvertData()
        {
            Logger.Info("=========================开始执行数据计算======================");
            String sql = string.Format("select * from syncDataRecord where type = '{0}' and status='1'", stationType);
            DataSet dsUnfinished = SqlHelper.Query(sql, targetDbConn);
            if (dsUnfinished.Tables[0].Rows.Count > 0)
            {
                foreach (DataRow dr in dsUnfinished.Tables[0].Rows)
                {
                    int syncCount = int.Parse(dr["syncCount"].ToString());
                    string date = dr["syncDate"].ToString();
                    string sqlStr = string.Format("SELECT * from DayAverage where datetime='{0}'", date);
                    DataSet ds = SqlHelper.Query(sqlStr, sourceDbConn);
                    if (ds.Tables.Count == 0 || ds.Tables[0].Rows.Count == 0)
                    {
                        Logger.Info(string.Format("未查到{0}数据，继续查找下一个时间点数据", date));
                        continue;
                    }

                    int total = int.Parse(dr["count"].ToString());
                    string sqlStr2 = string.Format("select csId as id from cityHourData WHERE datetime='{0}'", date);
                    if (!stationType.Equals("1"))
                    {
                        sqlStr2 = string.Format("select asId as id from areaHourData WHERE datetime='{0}'", date);
                    }

                    DataSet dsIds = SqlHelper.Query(sqlStr2, targetDbConn);
                    string[] ids = new string[dsIds.Tables[0].Rows.Count];
                    for (int row = 0; row < dsIds.Tables[0].Rows.Count; row++)
                    {
                        ids[row] = dsIds.Tables[0].Rows[row]["id"].ToString();
                    }


                    //开始计算数值
                    string syncStatus = "2";
                    int unFinishedNum = 0;
                    foreach (DataRow item in ds.Tables[0].Rows)
                    {
                        string id = item["ClientID"].ToString();
                        if (Array.IndexOf(ids, id) == -1)
                        {
                            string so2 = item["SO2"].ToString();
                            string no2 = item["NO2"].ToString();
                            string co = item["CO"].ToString();
                            string o3 = item["O3"].ToString();
                            string pm10 = item["PM10"].ToString();
                            string pm25 = item["PM25"].ToString();

                            double dso2 = IAQIHelper.Calc(float.Parse(ConvertData(so2, "SO2", date)) * cSO2, "SO2");
                            double dno2 = IAQIHelper.Calc(float.Parse(ConvertData(no2, "NO2", date)) * cNO2, "NO2");
                            double dco = IAQIHelper.Calc(float.Parse(ConvertData(co, "CO", date)) * cCO, "CO");
                            double do3 = IAQIHelper.Calc(float.Parse(ConvertData(o3, "O3", date)) * cO3, "O3");
                            double dpm10 = IAQIHelper.Calc(float.Parse(ConvertData(pm10, "PM10", date)) * cPM10, "PM10");
                            double dpm25 = IAQIHelper.Calc(float.Parse(ConvertData(pm25, "PM25", date)) * cPM25, "PM25");
                            int count = InsertData(id, dso2, dno2, do3, dco, dpm10, dpm25, date);
                            if (count > 0)
                            {
                                Logger.Info(string.Format("站点【{0}】{1}数据处理完成", id, date));
                            }
                            else
                            {
                                syncStatus = "1";
                                unFinishedNum++;
                                Logger.Info(string.Format("站点【{0}】{1}数据处理失败", id, date));
                            }
                        }
                    }
                    string updateSql = string.Format("update syncDataRecord set syncCount='{0}',status='{1}' where syncDate='{2}' and type='{3}'", total - unFinishedNum, syncStatus, date, stationType);
                    SqlHelper.ExecuteSql(updateSql, targetDbConn);
                }
            }
            else
            {
                Logger.Info("未找到需要计算的记录");
            }
            Logger.Info("========================执行数据计算结束========================");
        }

        /// <summary>
        /// 计算机过插入到数据库
        /// </summary>
        /// <param name="id"></param>
        /// <param name="so2"></param>
        /// <param name="no2"></param>
        /// <param name="o3"></param>
        /// <param name="co"></param>
        /// <param name="pm10"></param>
        /// <param name="pm25"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        private int InsertData(string id, double so2, double no2, double o3, double co, double pm10, double pm25, string date)
        {
            string sql = string.Format("insert into cityHourData (csid,pm25,pm10,so2,no2,co,o3,datetime) VALUES({0},{1},{2},{3},{4},{5},{6},'{7}')", id, pm25, pm10, so2, no2, co, o3, date);
            if (stationType.Equals("2"))
            {
                sql = string.Format("insert into areaHourData (asid,pm25,pm10,so2,no2,co,o3,datetime) VALUES({0},{1},{2},{3},{4},{5},{6},'{7}')", id, pm25, pm10, so2, no2, co, o3, date);

            }
            return SqlHelper.ExecuteSql(sql, targetDbConn);
        }

        /// <summary>
        /// P判断值是否满足计算要求，对不满足计算条件的值进行处理
        /// </summary>
        /// <param name="value"></param>
        /// <param name="type"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        private string ConvertData(string value, string type, string date)
        {
            if (null == value || value.Length == 0 || value.Equals("-1") || double.Parse(value)<=0)
            {
                //获取改时间所有站点的平均值
                string sql = string.Format("SELECT AVG({0}) from DayAverage where datetime='{1}' and {2}<>'-1' and {3}<>'0' and {4} is not NULL", type, date, type, type, type);
                value = SqlHelper.ExecuteScalar(sql, sourceDbConn).ToString();
            }

            if (type.Equals("SO2") && float.Parse(value) > 800)
            {
                //获取最近24小时平均值
                string sql = string.Format("SELECT AVG(so2) from DayAverage where datetime BETWEEN '{0}' AND '{1}' and so2<>'-1' and so2<>'0' and so2 is not NULL;", DateTime.Parse(date).AddDays(-1), date);
                value = SqlHelper.ExecuteScalar(sql, sourceDbConn).ToString();
            }
            return value;
        }

        /// <summary>
        /// 同步所有站点
        /// </summary>
        /// <returns>站点编号</returns>
        private int SyncAllStation()
        {
            //获取站点
            string sqlStr = "select ClientID,cnname,lng,lat from configMonAirStationInfoTJ";
            DataSet ds = SqlHelper.Query(sqlStr, sourceDbConn);
            if (ds.Tables[0].Rows.Count > 0)
            {
                foreach (DataRow dr in ds.Tables[0].Rows)
                {
                    SyncStation(dr);
                }
                return ds.Tables[0].Rows.Count;
            }
            else
            {
                Logger.Info("数据中未存在站点");
            }

            return 0;
        }

        /// <summary>
        /// 同步站点
        /// </summary>
        /// <param name="dr">站点数据</param>
        /// <returns></returns>
        private bool SyncStation(DataRow dr)
        {
            string cid = dr["ClientID"].ToString();
            string name = dr["cnname"].ToString();
            string lng = dr["lng"].ToString();
            string lat = dr["lat"].ToString();

            StringBuilder sb = new StringBuilder();
            if ("1".Equals(stationType))
            {
                //市控站点
                sb.Append(String.Format("if not exists (select * from cityStation where csID= '{0}') ", cid));
                sb.Append(String.Format("insert into cityStation(csID, csName, Lng, Lat, status) values('{0}', '{1}', '{2}', '{3}', 1) ", cid, name, lng, lat));
                sb.Append("else ");
                sb.Append(String.Format("update cityStation set csName = '{0}', Lng = '{1}', Lat = '{2}' where csID = '{3}'", name, lng, lat, cid));
            }
            else
            {
                //区控站点 
                sb.Append(String.Format("if not exists (select * from areaStation where asID= '{0})' ", cid));
                sb.Append(String.Format("insert into areaStation(asID, asName, Lng, Lat, status) values('{0}', '{1}', '{2}', '{3}', 1) ", cid, name, lng, lat));
                sb.Append("else ");
                sb.Append(String.Format("update areaStation set asName = '{0}', Lng = '{1}', Lat = '{2}' where asID = '{3}'", name, lng, lat, cid));

            }

            int count = SqlHelper.ExecuteSql(sb.ToString(), targetDbConn);
            if (count > 0)
            {
                Logger.Info(string.Format("站点{0}【{1}】同步成功", name, cid));
                return true;
            }
            else
            {
                Logger.Info(string.Format("站点{0}【{1}】同步失败，不再数据计算", name, cid));
                return false;
            }
        }

        #endregion
    }
}
